package org.hepeng.workx.mybatis.event.consumer;

import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.apache.ibatis.exceptions.ExceptionFactory;
import org.hepeng.workx.mybatis.binding.MapperRegistryGetMapperObjectProcessor;
import org.hepeng.workx.mybatis.event.listener.ExecuteEventListener;
import org.hepeng.workx.mybatis.event.listener.ExecuteEventListenerRegistry;
import org.hepeng.workx.mybatis.event.listener.MapperExecuteEventListener;
import org.hepeng.workx.util.ClassUtils;

import java.lang.reflect.Constructor;
import java.util.Objects;

/**
 * @author he peng
 */
public class EventConsumerBindObjectProcessor implements MapperRegistryGetMapperObjectProcessor {

    private ExecuteEventListenerRegistry executeEventListenerRegistry;

    public EventConsumerBindObjectProcessor(ExecuteEventListenerRegistry executeEventListenerRegistry) {
        this.executeEventListenerRegistry = executeEventListenerRegistry;
    }

    @Override
    public GetMapperPreProcessObject preProcess(GetMapperPreProcessObject preProcessObject) {
        Class<?> type = preProcessObject.getType();
        EventConsumerBind eventConsumerBind = type.getAnnotation(EventConsumerBind.class);
        if (Objects.nonNull(eventConsumerBind)) {
            ExecuteEventListener executeEventListener = new MapperExecuteEventListener(type);
            Class<? extends EventConsumer>[] consumerClasses = eventConsumerBind.value();
            try {
                for (Class<? extends EventConsumer> consumerClass : consumerClasses) {
                    Constructor<? extends EventConsumer> constructor = ConstructorUtils.getAccessibleConstructor(consumerClass);
                    if (Objects.nonNull(constructor)) {
                        EventConsumer eventConsumer = ConstructorUtils.invokeConstructor(consumerClass);
                        Class<?> genericClass = ClassUtils.getSingleGeneric(consumerClass, EventConsumer.class);
                        executeEventListener.addEventConsumer(genericClass , eventConsumer);
                    }
                }
                executeEventListenerRegistry.addExecuteEventListener(executeEventListener);
            } catch (Exception e) {
                throw ExceptionFactory.wrapException("Exception when process @" + EventConsumerBind.class.getName() , e);
            }
        }

        return preProcessObject;
    }

    @Override
    public GetMapperPostProcessObject postProcess(GetMapperPostProcessObject postProcessObject) {
        return postProcessObject;
    }
}
